﻿using CommonModel.Util;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace GXRTBTC.PublicClassLibrary.Model
{
    /// <summary>
    /// 台站告警匹配信息
    /// 1、位置对应前缀找到频率
    /// 2、位置对应前缀找到天线在位情况
    /// 3、频率匹配时间表（是否播出）
    /// 4、频率匹配节目信息
    /// 为了方便匹配，涉及到匹配的全部用字典形式
    /// 描述里说的位置，其实就是指具体的设备 工位号+系统=唯一的位置
    /// </summary>
    public class StationAlarmMatchInfo
    {
        /// <summary>
        /// 位置对应前缀找到频率
        /// </summary>
        public Dictionary<string, Dictionary<string, string>> positionToFrqPrefix { get; set; } = new();
        /// <summary>
        /// 位置对应前缀找到天线在位情况
        /// </summary>
        public Dictionary<string, Dictionary<string, bool>> positionToTxPrefix { get; set; } = new();
        /// <summary>
        /// 位置对应入射功率
        /// 目前来看，只针对1~3级台站数字电视，因为数字电视1+1切换器有时候无法提供天线信息，需要根据入射功率取判断，以便于做一个纠正，避免误告警
        /// </summary>
        public Dictionary<string, int> positionToIpower { get; set; } = new();

        /// <summary>
        /// 频率匹配位置信息，该位置为工位号+设备名称，一个频率可对应多个位置，多个频率也可能包含同一个位置
        /// 如：工位号+设备名称 0101040400_0x0707_1_FourFMSystemSwitcher_1
        /// 如：工位号+设备名称 0101040400_0x0201_1_trans0
        /// </summary>
        public Dictionary<string, Dictionary<string, string>> frqToPosition { get; set; } = new();

        /// <summary>
        /// 频率对应时间表是否告警
        /// key是频率
        /// 频率值
        /// 或者带有子系统编号前缀的频率值，如电视系统（3）-频率（21）（3_21）
        /// </summary>
        public Dictionary<string, bool> frqIntime { get; set; } = new();
        /// <summary>
        /// 根据频率匹配对应节目信息
        /// </summary>
        public Dictionary<string, Dictionary<string, string>> frqProgram { get; set; } = new();
        /// <summary>
        /// 工位号和频率对应
        /// </summary>
        public Dictionary<string, Dictionary<string, string>> positionIdToFrq { get; set; } = new();

        /// <summary>
        /// 根据位置，返回该位置是否应该告警
        /// </summary>
        /// <param name="position"></param>
        /// <param name="prefix"></param>
        /// <returns></returns>
        public bool GetPositionAlarm(string position, string prefix = "")
        {
            bool alarm = true;
            try
            {
                //获取频率
                string frq = GetFrq(position, prefix);

                //根据位置、前缀，去匹配天线，没有天线的直接告警
                if (positionToTxPrefix.ContainsKey(position) && positionToTxPrefix[position].Count > 0)
                {
                    //有可能获取不到，获取知道该频率被多少个位置播出
                    if (frqToPosition.ContainsKey(frq))
                    {
                        //得出有多少个位置（设备）播出该频率
                        Dictionary<string, string> positions = frqToPosition[frq];

                        //或告警，只要有要给告警，就告警
                        bool orAlarm = false;
                        //且告警，全部告警才告警
                        bool andAlarm = true;
                        //当前工位号告警情况
                        bool psAlarm = false;
                        //最大，最小工位号编号
                        int minpno = 1000;
                        int maxpno = 0;
                        //最大最小工位号
                        string minPosition = position;
                        string maxPosition = position;
                        //有入射功率的设备
                        Dictionary<string, int> hasIpowers = new();
                        //遍历positions位置
                        foreach (string positionIn in positions.Keys)
                        {
                            //该位置要有天线信息，否则认为是模拟的设备或者无天线信息，可能是静态数据节点，就直接跳过，默认告警
                            if (positionToTxPrefix.ContainsKey(positionIn) && positionToTxPrefix[positionIn].Count > 0)
                            {
                                //记录多个位置的最小工位编号 工位号格式为0101040400_0x0201_1，横杠最后一个就是编号，天线都不在位时最小编号的优先告警
                                string pno = positions[positionIn][(positions[positionIn].LastIndexOf('_') + 1)..];
                                //找出最小编号的位置
                                if (int.Parse(pno) < minpno)
                                {
                                    minpno = int.Parse(pno);
                                    minPosition = positionIn;
                                }
                                //找出最大编号的位置
                                if (int.Parse(pno) > maxpno)
                                {
                                    maxpno = int.Parse(pno);
                                    maxPosition = positionIn;
                                }

                                //判断是否有功率
                                if (positionToIpower.ContainsKey(positionIn))
                                {
                                    hasIpowers.TryAdd(positionIn, positionToIpower[positionIn]);
                                }

                                //如果刚好是当前位置，则判断是否告警
                                if (position.Equals(positionIn))
                                {
                                    psAlarm = positionToTxPrefix[positionIn].ContainsKey(prefix) ? positionToTxPrefix[positionIn][prefix] : positionToTxPrefix[positionIn].Values.ToList()[0];
                                }

                                //该位置是否拥有多个前置
                                List<string> prefixs = positionToTxPrefix[positionIn].Keys.ToList();
                                //多个前缀的情况，目前只有村级台站，所有告警都集中在切换器，四级台站切换器的数据都模拟到发射机了，不存在多个prefixs的情况
                                if (prefixs.Count > 1)
                                {
                                    //有多个位置，判断位置频率是否一致，一致则判断天线在位情况
                                    foreach (string prefixIn in prefixs)
                                    {
                                        if (frq.Equals(GetFrq(positionIn, prefixIn)))
                                        {
                                            //循环用或方法判断是否告警
                                            //tmpBool
                                            bool tb = (positionToTxPrefix[positionIn].ContainsKey(prefixIn) ? positionToTxPrefix[positionIn][prefixIn] : positionToTxPrefix[positionIn].Values.ToList()[0]);
                                            orAlarm = orAlarm || tb;
                                            andAlarm = andAlarm && tb;
                                        }
                                    }
                                    break;
                                }
                                else
                                {
                                    //只有一个前置，则直接赋值
                                    //循环用或方法判断是否告警
                                    //tmpBool
                                    bool tb = (positionToTxPrefix[positionIn].ContainsKey(prefix) ? positionToTxPrefix[positionIn][prefix] : positionToTxPrefix[positionIn].Values.ToList()[0]);
                                    orAlarm = orAlarm || tb;
                                    andAlarm = andAlarm && tb;
                                }
                            }
                        }

                        //如果多台都不告警即当前位置也不告警，就选择编号小的一台告警，如果当前position就是小的那台，那就告警
                        if (!psAlarm && !orAlarm)
                        {
                            //都没有告警，尝试通过是否有功率值去判断天线在哪个设备，有可能不是第一台，这里做一个判断，在就告警
                            if (hasIpowers.Count > 0)
                            {
                                psAlarm = hasIpowers.ContainsKey(position);
                            }
                            //没有功率信息，如果当前position就是小的那台，那就告警
                            else if (position.Equals(minPosition))
                            {
                                psAlarm = true;
                            }
                        }
                        //如果每台都告警即当前位置也告警，就选择编号最大的一台不告警，如果当前position就是大的那台，那就不告警
                        else if (psAlarm && andAlarm && position.Equals(maxPosition))
                        {
                            psAlarm = false;
                        }

                        alarm = psAlarm;
                    }
                    else
                    {
                        //20230810修改以下，默认先直接用第一组天线值，然后再进行判断前缀prefix的天线，暂时先放这个位置，后续如果根据需要，判断是否需要放到最外层作为默认值
                        if (positionToTxPrefix[position].Count > 0)
                        {
                            alarm = positionToTxPrefix[position].Values.ToList()[0];
                        }

                        //找不到频率信息
                        //如果有天线信息，尝试根据天线信息判断，天线在位则告警
                        //如果天线也没有？直接告警
                        if (positionToTxPrefix[position].ContainsKey(prefix))
                        {
                            alarm = (positionToTxPrefix[position].ContainsKey(prefix) ? positionToTxPrefix[position][prefix] : positionToTxPrefix[position].Values.ToList()[0]);
                        }
                    }
                }
                else
                {
                    //20230721 ysw新增判断
                    //0x0702 调频300W特殊处理，根据pair_count发射机组数量，判断是否该属性（前缀switch1、switch2、switch3）需要告警
                    //pair_count参数 发射机组数量（实际1+1套数） 0x0702主控有该参数，且全部关联到0x0702下每一台发射机
                    if ("".Equals(frq) && !"".Equals(prefix) && prefix.ToUpper().Contains("SWITCH") && position.ToUpper().Contains("_0X0702_"))
                    {
                        alarm = false;
                    }
                }
            }
            catch (Exception e)
            {
                Console.WriteLine("GetPositionAlarm错误，" + e);
            }
            return alarm;
        }

        /// <summary>
        /// 获取位置频率
        /// </summary>
        /// <param name="position"></param>
        /// <param name="prefix"></param>
        /// <returns></returns>
        public string GetFrq(string position, string prefix = "")
        {
            string frq = "";
            try
            {
                //匹配频率前置
                if (positionToFrqPrefix.ContainsKey(position) && positionToFrqPrefix[position].Count > 0)
                {
                    string prefixIn = "".Equals(prefix) ? positionToFrqPrefix[position].Keys.ToList()[0] : prefix;
                    frq = positionToFrqPrefix[position].ContainsKey(prefixIn) ? positionToFrqPrefix[position][prefixIn] : positionToFrqPrefix[position].Values.ToList()[0];

                    //20230721 ysw新增判断
                    //0x0702 调频300W特殊处理，根据pair_count发射机组数量，判断是否该属性（前缀switch1、switch2、switch3）需要告警
                    //pair_count参数 发射机组数量（实际1+1套数） 0x0702主控有该参数，且全部关联到0x0702下每一台发射机
                    if (!"".Equals(prefix) && prefix.ToUpper().Contains("SWITCH") && position.ToUpper().Contains("_0X0702_")
                        && !positionToFrqPrefix[position].ContainsKey(prefix))
                    {
                        frq = "";
                    }
                }
            }
            catch (Exception e)
            {
                Console.WriteLine("GetFrq错误，" + e);
            }
            return frq;
        }

        /// <summary>
        /// 根据工位号获取频率
        /// </summary>
        /// <param name="positionId"></param>
        /// <returns></returns>
        public string GetFrqForPositionId(string positionId)
        {
            string frq = "";
            try
            {
                //匹配频率前置
                if (positionIdToFrq.ContainsKey(positionId) && positionIdToFrq[positionId].Count > 0)
                {
                    frq = positionIdToFrq[positionId].Keys.ToList()[0];
                    if ("".Equals(frq) || "0".Equals(frq))
                    { 
                        //修改获取方式
                        foreach (string key in positionIdToFrq[positionId].Keys)
                        {
                            if (!"".Equals(key) && !"0".Equals(key))
                            {
                                frq = key;
                                break;
                            }
                        }
                    }
                }
            }
            catch (Exception e)
            {
                Console.WriteLine("GetFrq错误，" + e);
            }
            return frq;
        }

        /// <summary>
        /// 获取真实频率，没有返回空，而不是返回默认第一个频率
        /// </summary>
        /// <param name="position"></param>
        /// <param name="prefix"></param>
        /// <returns></returns>
        public string GetFrqReal(string position, string prefix = "")
        {
            string frq = "";
            try
            {
                //匹配频率前置
                if (positionToFrqPrefix.ContainsKey(position) && positionToFrqPrefix[position].Count > 0)
                {
                    string prefixIn = "".Equals(prefix) ? positionToFrqPrefix[position].Keys.ToList()[0] : prefix;
                    frq = positionToFrqPrefix[position].ContainsKey(prefixIn) ? positionToFrqPrefix[position][prefixIn] : frq;
                }
            }
            catch (Exception e)
            {
                Console.WriteLine("GetFrq错误，" + e);
            }
            return frq;
        }

        /// <summary>
        /// 获取位置所有频率
        /// </summary>
        /// <param name="position"></param>
        /// <param name="prefix"></param>
        /// <returns></returns>
        public List<string> GetFrqs(string position, string prefix = "")
        {
            List<string> frqs = new List<string>();
            try
            {
                //匹配频率前置
                if (positionToFrqPrefix.ContainsKey(position) && positionToFrqPrefix[position].Count > 0)
                {
                    string prefixIn = "".Equals(prefix) ? positionToFrqPrefix[position].Keys.ToList()[0] : prefix;
                    if (positionToFrqPrefix[position].ContainsKey(prefixIn))
                    {
                        frqs.Add(positionToFrqPrefix[position][prefixIn]);
                    }
                    else
                    { 
                        frqs = positionToFrqPrefix[position].Values.ToList();
                    }
                }
            }
            catch (Exception e)
            {
                Console.WriteLine("GetFrq错误，" + e);
            }
            return frqs;
        }

        /// <summary>
        /// 获取是否在时间表
        /// </summary>
        /// <param name="frq"></param>
        /// <returns></returns>
        public bool GetInTime(string frq, string subSysId = "")
        {
            bool inTime = true;
            string key = (subSysId == null || "".Equals(subSysId)) ? frq : subSysId + "_" + frq;
            if (frqIntime.ContainsKey(key))
            {
                inTime = frqIntime[key];
            }
            //加前缀找不到，就找频率
            else if (frqIntime.ContainsKey(frq))
            {
                inTime = frqIntime[frq];
            }
            return inTime;
        }

        /// <summary>
        /// 获取节目信息
        /// </summary>
        /// <param name="frq"></param>
        /// <returns></returns>
        public Dictionary<string, string> GetProgramInfo(string frq)
        {
            Dictionary<string, string> programInfo = null;
            if (frqProgram.ContainsKey(frq))
            {
                programInfo = frqProgram[frq];
            }
            return programInfo;
        }
    }
}
